MeshSprite.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /**
  2. * 根据给定的mesh数据/纹理/材质,渲染出结果
  3. */
  4. import {
  5. _decorator,
  6. CCBoolean,
  7. Component,
  8. EffectAsset,
  9. Material,
  10. Mesh,
  11. MeshRenderer,
  12. Node,
  13. SpriteFrame,
  14. Texture2D,
  15. UIMeshRenderer,
  16. utils,
  17. v3,
  18. v4,
  19. Vec3,
  20. } from 'cc';
  21. import earcut from './EarCut';
  22. const { ccclass, property, executeInEditMode, menu } = _decorator;
  23. @ccclass('MeshSprite')
  24. @executeInEditMode
  25. @menu('2D/MeshSprite(Mesh精灵)')
  26. export class MeshSprite extends Component {
  27. @property(EffectAsset)
  28. private _effectAsset: EffectAsset = null!;
  29. @property({
  30. type: EffectAsset,
  31. tooltip: '渲染effectAssets文件,拖入curvetexture-sprite即可',
  32. displayName: 'effect asset文件',
  33. })
  34. public get effectAsset(): EffectAsset {
  35. return this._effectAsset;
  36. }
  37. public set effectAsset(value: EffectAsset) {
  38. if (value !== this._effectAsset) {
  39. this._mat?.destroy();
  40. this._mat = null;
  41. this._effectAsset?.destroy();
  42. this._effectAsset = value;
  43. this._refreshAll();
  44. }
  45. }
  46. @property(SpriteFrame)
  47. private _spriteFrame: SpriteFrame = null!;
  48. @property({
  49. type: SpriteFrame,
  50. tooltip: '纹理文件,拖入spriteframe即可',
  51. displayName: '纹理文件',
  52. })
  53. get spriteFrame(): SpriteFrame {
  54. return this._spriteFrame;
  55. }
  56. set spriteFrame(value: SpriteFrame) {
  57. if (this._spriteFrame !== value) {
  58. this._spriteFrame = value;
  59. if (value) {
  60. if (
  61. (value.originalSize.width & (value.originalSize.width - 1)) !== 0 ||
  62. (value.originalSize.height & (value.originalSize.height - 1)) !== 0
  63. ) {
  64. console.warn(`纹理尺寸(${value.originalSize.width}x${value.originalSize.height})不是2的幂,请修改。`);
  65. return;
  66. }
  67. }
  68. if (this._spriteFrame) {
  69. this._curve_width = this._spriteFrame.originalSize.width;
  70. this._curve_height = this._spriteFrame.originalSize.height;
  71. }
  72. this._refreshAll();
  73. }
  74. }
  75. @property({})
  76. private _updownFix: boolean = false;
  77. @property({
  78. tooltip: `是否上下翻转纹理,默认false`,
  79. displayName: `是否上下翻转`,
  80. })
  81. get updownFix() {
  82. return this._updownFix;
  83. }
  84. set updownFix(value) {
  85. this._updownFix = value;
  86. this._refreshAll();
  87. }
  88. private _meshRender: MeshRenderer = null;
  89. private _uiMeshRender: UIMeshRenderer = null;
  90. private _mat: Material = null;
  91. private _vertexes: Vec3[] = [
  92. v3(-200, 200, 0), // 左上
  93. v3(-200, -200, 0), // 左下
  94. v3(200, -200, 0), // 右下
  95. v3(200, 200, 0), // 右上
  96. ];
  97. private _curve_width = 0;
  98. private _curve_height = 0;
  99. private _uvs: number[] = [];
  100. protected onEnable(): void {
  101. this._refreshAll();
  102. }
  103. public setVertexes(vertexes: Vec3[]) {
  104. this._vertexes = vertexes;
  105. this._refreshAll();
  106. }
  107. private _refreshAll() {
  108. if (!this._spriteFrame) {
  109. console.warn(`没有spriteFrame,请拖入纹理`);
  110. return;
  111. }
  112. if (!this._effectAsset) {
  113. console.warn(`没有effectAsset,请拖入effect文件 curvetexture-sprite`);
  114. return;
  115. }
  116. this._meshRender = this.node.getComponent(MeshRenderer);
  117. if (!this._meshRender) {
  118. this._meshRender = this.node.addComponent(MeshRenderer);
  119. }
  120. this._uiMeshRender = this.node.getComponent(UIMeshRenderer);
  121. if (!this._uiMeshRender) {
  122. this._uiMeshRender = this.node.addComponent(UIMeshRenderer);
  123. }
  124. this._mat = this._meshRender.getMaterialInstance(0) as Material;
  125. if (!this._mat) {
  126. this._mat = new Material();
  127. this._mat.initialize({
  128. effectAsset: this._effectAsset,
  129. defines: {
  130. USE_TEXTURE: true,
  131. },
  132. });
  133. this._meshRender.setMaterialInstance(this._mat, 0);
  134. }
  135. this._spriteFrame.texture.setWrapMode(
  136. Texture2D.WrapMode.REPEAT,
  137. Texture2D.WrapMode.REPEAT,
  138. Texture2D.WrapMode.REPEAT
  139. );
  140. this._curve_width = this._spriteFrame.originalSize.width;
  141. this._curve_height = this._spriteFrame.originalSize.height;
  142. this._mat.setProperty('mainTexture', this._spriteFrame.texture, 0);
  143. const uv = this._spriteFrame.uv;
  144. const uv_x = uv[0]; // ul
  145. const uv_y = uv[1]; // vb
  146. const uv_w = uv[6] - uv[0]; // ur - ul
  147. const uv_h = uv[5] - uv[1]; // vt - vb
  148. const altlasUV = v4(uv_x, uv_y, uv_w, uv_h);
  149. // console.log(this.node.name + ' altlasUV', altlasUV);
  150. this._mat.setProperty('altlasUV', altlasUV, 0);
  151. const positions: number[] = [];
  152. // const positions2d: number[] = [];
  153. for (let i = 0; i < this._vertexes.length; i++) {
  154. const v = this._vertexes[i];
  155. positions.push(v.x, v.y, v.z);
  156. // positions2d.push(v.x, v.y);
  157. }
  158. // if (this._uvs.length <= 8) {
  159. this._uvs = this._calculateUVs();
  160. // }
  161. const start = performance.now();
  162. const indices: number[] = earcut(positions, null, 3);
  163. const end = performance.now();
  164. // console.log(`earcut triangulation 解析转换为渲染三角形索引耗时 took ${(end - start).toFixed(2)} ms`);
  165. // console.log(this.node.name + ' indices ', indices);
  166. let mesh = utils.MeshUtils.createMesh({
  167. positions: positions,
  168. uvs: this._uvs,
  169. indices: indices,
  170. });
  171. if (this._meshRender!.mesh) {
  172. this._meshRender!.mesh.destroy();
  173. }
  174. this._meshRender!.mesh = mesh;
  175. }
  176. private _calculateUVs() {
  177. let uvs: number[] = [];
  178. if (!this._spriteFrame || this._vertexes.length === 0) {
  179. return uvs;
  180. }
  181. for (let i = 0; i < this._vertexes.length; i++) {
  182. const d = this._vertexes[i];
  183. const u = d.x / this._curve_width;
  184. let v = 1.0 - d.y / this._curve_height;
  185. if (this._updownFix) {
  186. v = d.y / this._curve_height;
  187. }
  188. uvs.push(u, v);
  189. }
  190. return uvs;
  191. }
  192. }